package com.lebang.medicalInquiry.component;

import com.aliyun.oss.ClientException;
import com.aliyun.oss.HttpMethod;
import com.aliyun.oss.OSSClient;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.common.utils.BinaryUtil;
import com.aliyun.oss.common.utils.IOUtils;
import com.aliyun.oss.event.ProgressEventType;
import com.aliyun.oss.model.*;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.auth.sts.AssumeRoleRequest;
import com.aliyuncs.auth.sts.AssumeRoleResponse;
import com.aliyuncs.http.MethodType;
import com.aliyuncs.http.ProtocolType;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.profile.IClientProfile;


import com.lebang.medicalInquiry.utils.TextUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;

import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.time.LocalDateTime;
import java.util.*;

/**
 * @program: LazyAssistant
 * @description: oss 文件存储
 * @author: tony
 * @create: 2019-12-10 13:45
 **/
@Slf4j
@Component
public class OssComponent {
    private static final String END_POINT = "oss-cn-shenzhen.aliyuncs.com";
    private static final String IMAGE = "image";
    private static final String VIDEO = "video";
    private static final String BMP = ".bmp";
    private static final String GIF = ".gif";
    private static final String JPEG = ".jpeg";
    private static final String HTML = ".html";
    private static final String TXT = ".txt";
    private static final String JPG = ".jpg";
    private static final String PNG = ".png";
    private static final String VSD = ".vsd";
    private static final String PPTX = ".pptx";
    private static final String PPT = ".ppt";
    private static final String DOC = ".doc";
    private static final String DOCX = ".docx";
    private static final String XML = ".xml";
    private static final String APK = ".apk";
    /**
     * endpoint以杭州为例，其它region请按实际情况填写
     */
    private static final String EPOINT = "http://" + END_POINT;

    /**
     * accessKey
     */
    private final String accessKeyId = "LTAI5tDhr4yFGwEwCRDDJ8Mt";
    private final String accessKeySecret = "OV4nWTwnAhWGvgd5WhlZfPiEcsHQYO";

    /**
     * 角色
     */
    private static final String ARN = "acs:ram::1818001933570015:role/lbramoss";
    private static final String ARNNAME = "lbramoss";

    /**
     * 空间
     */
    private static String bucketName = "medical-digital";


//    public static String accessHost = "https://medical-digital.oss-cn-shenzhen.aliyuncs.com";
    public static String accessHost = "http://mataimg.digitalmate.cn";
    private OSSClient ossClient;

    private long bytesWritten = 0;
    private long totalBytes = -1;
    private boolean succeed = false;

    public void init() {
        ossClient = new OSSClient(EPOINT, accessKeyId, accessKeySecret);
        if (ossClient.doesBucketExist(bucketName)) {
            log.info("您已经创建Bucket：" + bucketName + "。");
        } else {
            log.info("您的Bucket不存在，创建Bucket：" + bucketName + "。");
            ossClient.createBucket(bucketName);
        }
    }

    public String upload2Oss1(MultipartFile file, String folder, String fileName, SseEmitter sseEmitter) {
        init();

        String type = file.getContentType();
        String originalFilename = TextUtil.isEmpty(file.getOriginalFilename()) == true ? file.getName() : file.getOriginalFilename();
        String substring = originalFilename.substring(originalFilename.lastIndexOf(".")).toLowerCase();
        String targetName = UUID.randomUUID().toString().replaceAll("-", "") + substring;
        String name = TextUtil.isEmpty(fileName) ? UUID.randomUUID().toString().replaceAll("-", "") + substring : fileName;
        try {
            /**
             * 文件存储目录
             */
            String fileDir = folder + "/" + getType(type);
            InputStream inputStream = file.getInputStream();
            this.uploadFile2Oss(inputStream, fileDir, name);
            String sourceName = accessHost + "/" + fileDir + "/" + name;
            if ("image/webp".equals(type)|| "image/jpg".equals(type) || "image/jpeg".equals(type) || "image/png".equals(type)) {
                sourceName = getSouceName(fileDir, targetName, name);
                //删除旧的照片
                delete(accessHost + fileDir + "/" + name);
            }
            return sourceName;
        } catch (Exception e) {
            e.printStackTrace();
            log.info("图片上传失败");
        }
        return null;
    }

    /**
     * 普通文件上传
     */
    public String upload2Oss(MultipartFile file, String folder, String fileName) {
        init();

        String type = file.getContentType();
        String originalFilename = TextUtil.isEmpty(file.getOriginalFilename()) == true ? file.getName() : file.getOriginalFilename();
        String substring = originalFilename.substring(originalFilename.lastIndexOf(".")).toLowerCase();
        String targetName = UUID.randomUUID().toString().replaceAll("-", "") + substring;
        String name = TextUtil.isEmpty(fileName) ? UUID.randomUUID().toString().replaceAll("-", "") + substring : fileName;
        try {
            /**
             * 文件存储目录
             */
            String fileDir = folder + "/" + getType(type);
            InputStream inputStream = file.getInputStream();
            this.uploadFile2Oss(inputStream, fileDir, name);
            String sourceName = accessHost + "/" + fileDir + "/" + name;
            if ("image/webp".equals(type) || "image/jpeg".equals(type) || "image/png".equals(type)) {
                sourceName = getSouceName(fileDir, targetName, name);
                //删除旧的照片
                delete(accessHost + fileDir + "/" + name);
            }
            return sourceName;
        } catch (Exception e) {
            e.printStackTrace();
            log.info("图片上传失败");
        }
        return null;
    }

    // 获取重新压缩的图片地址
    private String getSouceName(String fileDir, String tatgetName, String souceName) {

        // 进行解析
        String targetName = fileDir + "/" + tatgetName;
        String sourceName = fileDir + "/" + souceName;
        StringBuilder processBuildStr = new StringBuilder();
        Formatter styleFormatter = new Formatter(processBuildStr);
        String styleType = "image/format,webp/";
        String sourceImage = accessHost + "/" + fileDir + "/" + tatgetName;
        styleFormatter.format("%s|sys/saveas,o_%s,b_%s", styleType,
                BinaryUtil.toBase64String(targetName.getBytes()),
                BinaryUtil.toBase64String(bucketName.getBytes()));

        ProcessObjectRequest request = new ProcessObjectRequest(bucketName, sourceName, processBuildStr.toString());
        GenericResult processResult = ossClient.processObject(request);
        String json = null;
        try {
            json = IOUtils.readStreamAsString(processResult.getResponse().getContent(), "UTF-8");
            processResult.getResponse().getContent().close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return sourceImage;
    }

    // 获取重新压缩的图片地址
    private void getThumbnail(String key) {


        // 将图片缩放为固定宽高100 px后，再旋转90°。
        String style = "image/resize,m_fixed,w_100,h_100/rotate,90";
        // 指定签名URL过期时间为10分钟。
        Date expiration = new Date(System.currentTimeMillis() + 1000 * 60 * 10);
        GeneratePresignedUrlRequest req = new GeneratePresignedUrlRequest(bucketName, key, HttpMethod.GET);
        req.setExpiration(expiration);
        req.setProcess(style);
        URL signedUrl = ossClient.generatePresignedUrl(req);
        System.out.println(signedUrl);

    }

    public void delete(String url) {
        init();
        String substring = url.substring(accessHost.length());
        // 删除文件或目录。如果要删除目录，目录必须为空。
        ossClient.deleteObject(bucketName, substring);
        // 关闭OSSClient。
        ossClient.shutdown();
    }

    /**
     * 上传文件到指定的oss文件服务器目录中
     */
    public String uploadFile2Oss(InputStream inputStream, String folder, String fileName) {
        String ret = "";
        try {
            //创建上传Object的Metadata
            ObjectMetadata objectMetadata = new ObjectMetadata();
            objectMetadata.setContentLength(inputStream.available());
            objectMetadata.setCacheControl("public");
            String substring = fileName.substring(fileName.lastIndexOf("."));
            objectMetadata.setContentType(getContentType(substring));
            objectMetadata.setContentDisposition("inline;filename=" + fileName);
            //上传文件
            PutObjectResult putResult = ossClient.putObject(bucketName, folder + "/" + fileName, inputStream, objectMetadata);
            ret = putResult.getETag();
        } catch (IOException e) {
            log.error(e.getMessage(), e);
        } finally {
            try {
                if (inputStream != null) {
                    inputStream.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return ret;
    }


    /**
     * 上传文件到指定的oss文件服务器目录中
     */
    public String uploadStream(InputStream inputStream, String folder, String fileName) {
        init();
        String ret = "";
        try {
            //创建上传Object的Metadata
            ObjectMetadata objectMetadata = new ObjectMetadata();
            objectMetadata.setContentLength(inputStream.available());
            objectMetadata.setCacheControl("public");
            String substring = fileName.substring(fileName.lastIndexOf("."));
            objectMetadata.setContentType(getContentType(substring));
            objectMetadata.setContentDisposition("inline;filename=" + fileName);
            //上传文件
            ossClient.putObject(new PutObjectRequest(bucketName, folder + "/" + fileName, inputStream, objectMetadata));
            return accessHost + "/" + folder + "/" + fileName;
        } catch (IOException e) {
            log.error(e.getMessage(), e);
        } finally {
            try {
                if (inputStream != null) {
                    inputStream.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return ret;
    }


    /**
     * Description: 判断OSS服务文件上传时文件的contentType
     *
     * @param filenameExtension 文件后缀
     * @return String
     */
    public static String getContentType(String filenameExtension) {

        if (".bmp".equalsIgnoreCase(filenameExtension)) {
            return "image/bmp";
        } else if (".gif".equalsIgnoreCase(filenameExtension)) {
            return "image/gif";
        } else if (!".jpeg".equalsIgnoreCase(filenameExtension) && !".jpg".equalsIgnoreCase(filenameExtension) && !".png".equalsIgnoreCase(filenameExtension) && !".jpe".equalsIgnoreCase(filenameExtension)) {
            if (".html".equalsIgnoreCase(filenameExtension)) {
                return "text/html";
            } else if (".txt".equalsIgnoreCase(filenameExtension)) {
                return "text/plain";
            } else if (".vsd".equalsIgnoreCase(filenameExtension)) {
                return "application/vnd.visio";
            } else if (!".pptx".equalsIgnoreCase(filenameExtension) && !".ppt".equalsIgnoreCase(filenameExtension)) {
                if (!".docx".equalsIgnoreCase(filenameExtension) && !".doc".equalsIgnoreCase(filenameExtension)) {
                    if (".xml".equalsIgnoreCase(filenameExtension)) {
                        return "text/xml";
                    } else if (".pdf".equalsIgnoreCase(filenameExtension)) {
                        return "application/pdf";
                    } else if (".svg".equalsIgnoreCase(filenameExtension)) {
                        return "image/svg+xml";
                    } else {
                        return ".zip".equalsIgnoreCase(filenameExtension) ? "application/x-zip-compressed" : "application/otcet-stream";
                    }
                } else {
                    return "application/msword";
                }
            } else {
                return "application/vnd.ms-powerpoint";
            }
        } else {
            return "image/jpg";
        }
    }


    /**
     * 获取存储文件类型文件夹
     *
     * @param type
     * @return
     */
    private String getType(String type) {
        String prefix;
        if (type.contains(VIDEO)) {
            prefix = "video";
        } else if (type.contains(IMAGE)) {
            prefix = "image";
        } else {
            prefix = "files";
        }
        return prefix;
    }


    public String getPresignedUploadUrl(String name, String contentType) {
        init();
        Date expiration = new Date(System.currentTimeMillis() + 3600 * 1000);
        try {
            URL url = generatePresignedUrl(bucketName, contentType, name, expiration, HttpMethod.PUT);
            String path = url.getPath();
            return url.toString();
        } catch (OSSException e) {
            log.error("授权地址获取失败:", e);
            return null;
        }
    }


    public URL generatePresignedUrl(String bucketName, String contentType, String key, Date expiration, HttpMethod method)
            throws ClientException {
        GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(bucketName, key);
        request.setExpiration(expiration);
        request.setMethod(method);
        request.setContentType("video/mp4");
        return ossClient.generatePresignedUrl(request);
    }


    public Map buildAliyunStsCredentials() throws ClientException, com.aliyuncs.exceptions.ClientException {
        // STS,这里我以杭州举例,具体你的Bucket地域节点是哪里的就填哪里
//        DefaultProfile.addEndpoint("", "", "Sts", "sts.cn-shenzhen.aliyuncs.com");
        //这里需要填充你子账户的accessKeyId与accessKeySecret
        DefaultProfile.addEndpoint("shenzhen", "Sts", "oss-cn-shenzhen.aliyuncs.com");
        IClientProfile profile = DefaultProfile.getProfile("cn-shenzhen", accessKeyId, accessKeySecret);
        DefaultAcsClient client = new DefaultAcsClient(profile);
        final AssumeRoleRequest request = new AssumeRoleRequest();
        request.setMethod(MethodType.POST);
        request.setProtocol(ProtocolType.HTTPS);
        //设置临时访问凭证的有效时间为3600秒
        request.setDurationSeconds(900L);
        // 要扮演的角色ID-刚才你创建的角色详情里面ARN
        request.setRoleArn(ARN);
        // 要扮演的角色名称-刚才你创建的角色详情里面角色名称
        request.setRoleSessionName(ARNNAME);
        // request.setPolicy(policy);
        // 生成临时授权凭证
        final AssumeRoleResponse response = client.getAcsResponse(request);
        // 临时凭据AccessKeyId
        String appKey = response.getCredentials().getAccessKeyId();
        // 临时凭据AccessKeySecret
        String appSecret = response.getCredentials().getAccessKeySecret();
        // 临时凭据SecurityToken
        String securityToken = response.getCredentials().getSecurityToken();
//        2022-07-15T08:50:21Z

//        String expiration = response.getCredentials().getExpiration();
        //OSS底层限制了时间这边直接加上5小时
        String expiration = LocalDateTime.now().plusHours(5).toString();
//        String url = authorization(securityToken, appKey, appSecret, fileName);
        Map<String, Object> map = new HashMap<>();
        map.put("accessKeyId", appKey);
        map.put("accessKeySecret", appSecret);
        map.put("stsToken", securityToken);
        map.put("bucket", bucketName);
        map.put("region", "oss-cn-shenzhen");
        map.put("expiration", expiration);
        return map;
    }

}
